package service

import (
	"context"
	"encoding/json"
	"fmt"
	"fx_swift_agent/api"
	"fx_swift_agent/internal/model"
	"fx_swift_agent/pkg/code"
	"fx_swift_agent/pkg/global"
	"fx_swift_agent/pkg/gorsa"
	"fx_swift_agent/pkg/internalerrors"
	"fx_swift_agent/pkg/logger"
	"fx_swift_agent/pkg/page"
	"fx_swift_agent/pkg/utils"
	"github.com/gogf/gf/v2/container/gvar"
	"github.com/gogf/gf/v2/database/gdb"
	"github.com/gogf/gf/v2/frame/g"
	"github.com/golang-module/carbon/v2"
	"github.com/shopspring/decimal"
	"github.com/spf13/cast"
)

type ICardSrv interface {
	// 发卡
	CreateCard(ctx context.Context, req *api.CreateCardReq) error

	// 卡管理列表
	CardList(ctx context.Context, req *api.CardListReq) (*page.Collection[*api.CardListRes], error)

	// 卡详情
	GetCardDetails(ctx context.Context, cardId string) (*api.GetCardDetailsRes, error)

	// 卡交易列表
	CardTradeList(ctx context.Context, req *api.CardTradeListReq) (*page.Collection[*api.CardTradeListRes], error)

	// 充值
	CardRecharge(ctx context.Context, req *api.CardRechargeReq) error

	// 操作卡状态
	OperatorCardState(ctx context.Context, state, cardId string) error

	// 获取代理商余额和卡使用次数(免费的)
	GetAgentBalanceInfo(ctx context.Context) (*api.GetAgentBalanceInfoRes, error)

	// 获取卡头信息
	GetCardHead(ctx context.Context) (string, error)

	// 持卡人申请
	CardHolder(ctx context.Context, req *api.CardHolderReq) (string, error)

	// 获取持卡人列表
	GetCardHolderList(ctx context.Context, req *api.GetCardHolderListReq) (*page.Collection[*api.GetCardHolderListRes], error)

	// 持卡人详情
	CardHolderDetails(ctx context.Context, cardUserId string) (*api.CardHolderDetailsRes, error)

	// 删除持卡人
	DeleteCardHolder(ctx context.Context, cardUserId string) error

	// 获取卡图
	GetCardImage(ctx context.Context, cardId string) (*api.GetCardImageRes, error)

	// 获取代理商卡余额
	GetAgentCardBalance(ctx context.Context) (string, error)

	// 获取美国各州信息
	GetUSAStatInfo(ctx context.Context) ([]*api.GetUSAStatInfoRes, error)

	// 卡交易退款
	CardTradeRefundList(ctx context.Context, req *api.CardTradeRefundListReq) (*page.Collection[*api.CardTradeRefundListRes], error)

	// 退款
	CardRefund(ctx context.Context, req *api.CardRefundReq) error

	// 销卡申请
	CloseCard(ctx context.Context, req *api.CloseCardReq) error

	// 通过卡头获取对应的持卡人信息集合
	GetCardHeadToInfo(ctx context.Context, headStr string) ([]*api.GetCardHeadToInfoRes, error)

	// 手动充值记录
	ManualCardRechargeRecord(ctx context.Context, req *api.ManualCardRechargeRecordReq) error

	// 手动扣除代理商金额
	ManualDeductionAgentBalance(ctx context.Context, req *api.ManualDeductionAgentBalanceReq) error
}

type cardSrv struct {
}

func NewCardSrv() ICardSrv {
	return &cardSrv{}
}

// 发卡
func (c *cardSrv) CreateCard(ctx context.Context, req *api.CreateCardReq) error {
	var (
		account        string
		err            error
		agentObj       *model.FxAgent
		accountObj     *model.FxAccount
		managementObj  *model.FxAgentManagement
		managementFee  float64
		finalBalance   float64
		url            = "/api/vas/card/apply"
		dataContent    string
		pubdecrypt_str string
		resp           *api.CardApplyVoRes
		endDate        string
	)
	account = ctx.Value("Account").(string)
	if err = global.GFDB.Model("fx_agent").Where("account", account).Scan(&agentObj); err != nil {
		logger.SugarLogger.Error(err)
		return internalerrors.New(code.ErrUnknown, "发卡失败")
	}
	if agentObj == nil {
		return internalerrors.New(code.ErrUnknown, "该代理商存在异常")
	}
	if global.ViperObj.GetBool("card.card_flag") {
		if err = global.GFDB.Model("fx_agent_management").Where("account", account).
			Scan(&managementObj); err != nil {
			logger.SugarLogger.Error(err)
			return internalerrors.New(code.ErrUnknown, "发卡失败")
		}
		managementFee, _ = managementObj.ManagementFee.Float64()
		if managementFee == 0 {
			return internalerrors.New(code.ErrUnknown, "请先交清帐户管理费")
		}
	}
	if err = global.GFDB.Ctx(ctx).Model("fx_account").
		Where("account=?", account).Scan(&accountObj); err != nil {
		return internalerrors.New(code.ErrUnknown, err.Error())
	}

	if accountObj.Balance.LessThanOrEqual(decimal.NewFromFloat(0.0)) {
		return internalerrors.New(code.ErrUnknown, "帐号余额不足，请先充值")
	}

	finalBalance = agentObj.Fee * cast.ToFloat64(req.AuthLimitAmount)

	if req.CardHead == "522981" {
		req.CardUserId = ""
	}
	if GetNumerFirst(req.CardHead) == "4" {
		endDate = carbon.Now().AddDays(720).ToDateString()
	} else if GetNumerFirst(req.CardHead) == "5" {
		endDate = carbon.Now().AddDays(720).ToDateString()
	}
	reqObj := api.CardApplyReq{
		UserReqNo:           utils.GetHashCode(utils.GenerateCode32()),
		LocalCurrency:       req.LocalCurrency,
		StartDate:           carbon.Now().ToDateString(),
		EndDate:             endDate,
		AuthLimitAmount:     req.AuthLimitAmount,
		CardAlias:           req.CardAlias,
		EnableCurrencyCheck: 0,
		EnableMultiUse:      "1",
		BinRangeId:          req.CardHead,
		ChannelType:         "1",
		CardUserId:          req.CardUserId,
	}
	g.Dump(reqObj)
	dataContent, err = OperatorParams(global.ViperObj.GetString("gep.url")+url, reqObj)
	if err != nil {
		return internalerrors.New(code.ErrUnknown, err.Error())
	}
	// 公钥解密
	pubdecrypt_str, err = gorsa.PublicDecrypt(dataContent, gorsa.GetPublicKeyStr())
	if err != nil {
		return internalerrors.New(code.ErrUnknown, err.Error())
	}
	err = json.Unmarshal([]byte(pubdecrypt_str), &resp)
	if err != nil {
		return internalerrors.New(code.ErrUnknown, err.Error())
	}
	if len(pubdecrypt_str) != 0 {
		if _, err = global.GFDB.Ctx(ctx).Model("fx_card_info").Insert(&model.FxCardInfo{
			Email:         req.Email,
			CardId:        resp.CardId,
			CardUserId:    req.CardUserId,
			CardAlias:     req.CardAlias,
			Account:       ctx.Value("Account").(string),
			CardNo:        resp.CardNo,
			LocalCurrency: req.LocalCurrency,
			CardVerifyNo:  resp.CardVerifyNo,
			Expiration:    resp.CardExpiryDate,
			CardStatus:    "3",
			CardArea:      req.CardArea,
			CardHead:      req.CardHead,
			BusinessScene: req.BusinessScene,
		}); err != nil {
			logger.SugarLogger.Error(err.Error())
			return internalerrors.New(code.ErrUnknown, "开卡申请失败")
		}
		err = requestCardInfo(resp.CardId)

		if err = DeductionBalance(finalBalance, account, "admin", model.Fee, "充值手续费"); err != nil {
			return internalerrors.New(code.ErrUnknown, err.Error())
		}
		if err = DeductionAgentBalance(cast.ToFloat64(req.AuthLimitAmount), account, model.Transfer, "转账"); err != nil {
			return internalerrors.New(code.ErrUnknown, err.Error())
		}
		if agentObj.CardOpeningFee > 0 {
			if err = DeductionBalance(agentObj.CardOpeningFee, account, "admin", model.OpenCard, "开卡费"); err != nil {
				return internalerrors.New(code.ErrUnknown, err.Error())
			}
		}
	}
	return err
}

// 卡管理列表
func (c *cardSrv) CardList(ctx context.Context, req *api.CardListReq) (*page.Collection[*api.CardListRes], error) {
	var (
		err        error
		resultList []*api.CardListRes
		total      int
		account    string
	)
	account = ctx.Value("Account").(string)

	collectionDto := &page.Collection[*api.CardListRes]{}
	collectionDto.Page = req.Page
	collectionDto.PageSize = req.PageSize

	mod := global.GFDB.Ctx(ctx).Model("fx_card_info fci").
		LeftJoin("fx_cardholder fc", "fci.card_user_id = fc.card_user_id")
	mod.Fields("fci.card_id,fci.card_no,fci.balance_amt as balance,fc.first_name,fc.last_name," +
		"fci.expiration,fci.create_card_time,fci.card_status as state")
	if len(req.CardNo) > 0 {
		mod.WhereLike("fci.card_no", "%"+req.CardNo+"%")
	}
	if len(req.Name) > 0 {
		mod.WhereLike("concat(fc.first_name,fc.last_name)", "%"+req.Name+"%")
	}
	if len(req.StartTime) > 0 && len(req.EndTime) > 0 {
		mod.Where("fci.create_card_time >=? and fci.create_card_time < ?", req.StartTime+" 00:00:00", req.EndTime+" 23:59:59")
	}
	mod.Where("fci.account=?", account)
	mod.Order("fci.create_card_time desc")
	mod.Limit(int(page.PageToOffset(req.Page, req.PageSize)), cast.ToInt(req.PageSize))
	err = mod.ScanAndCount(&resultList, &total, false)
	collectionDto.TotalPage = page.GetTotalPage(req.Page, req.PageSize, cast.ToInt64(total))

	if err != nil {
		return nil, internalerrors.New(code.ErrUnknown, "数据查询异常")
	}
	collectionDto.Total = cast.ToInt64(total)
	collectionDto.List = resultList

	return collectionDto, err
}

// 卡详情
func (c *cardSrv) GetCardDetails(ctx context.Context, cardId string) (*api.GetCardDetailsRes, error) {
	type DbVo struct {
		CardId       string `json:"card_id"`
		CardUserId   string `json:"card_user_id"`
		CardNo       string `json:"card_no"`
		CardStatus   string `json:"card_status"`
		BalanceAmt   string `json:"balance_amt"`
		CardAlias    string `json:"card_alias"`
		Expiration   string `json:"expiration"`
		CardVerifyNo string `json:"card_verify_no"`
		Email        string `json:"email"`
	}
	var (
		err             error
		dbVo            *DbVo
		cardTradeDbList []*model.FxCardTradeRecord
		cardTreadList   = make([]*api.CardTradeList, 0)
		cardHolderObj   model.FxCardholder
		result          = &api.GetCardDetailsRes{}
		finalBalance    float64
		redisResult     *gvar.Var
	)
	err = requestCardInfo(cardId)

	if err = global.GFDB.Ctx(ctx).Model("fx_card_info").
		Where("card_id=?", cardId).Scan(&dbVo); err != nil {
		logger.SugarLogger.Error(err)
		return nil, internalerrors.New(code.ErrUnknown, "读取数据异常")
	}
	if dbVo == nil {
		return nil, internalerrors.New(code.ErrUnknown, "卡号异常")
	}
	if len(dbVo.CardUserId) > 0 {
		// 获取持卡人账单地址
		if err = global.GFDB.Ctx(ctx).Model("fx_cardholder").
			Where("card_user_id=?", dbVo.CardUserId).Scan(&cardHolderObj); err != nil {
			return nil, internalerrors.New(code.ErrUnknown, err.Error())
		}

		if err = global.GFDB.Ctx(ctx).Model("fx_card_trade_record").
			Where("card_id=?", cardId).Order("occur_time desc").Limit(10).Scan(&cardTradeDbList); err != nil {
			return nil, internalerrors.New(code.ErrUnknown, err.Error())
		}
	}
	if len(cardTradeDbList) > 0 {
		for _, value := range cardTradeDbList {
			cardTreadList = append(cardTreadList, &api.CardTradeList{
				TradeTime:    value.CreatedAt,
				Amount:       value.TransCurrencyAmt,
				MerchantName: value.MerchantName,
				TradeType:    value.TransType,
				State:        value.TransStatus,
			})
		}
		result.CardTradeList = cardTreadList
	}
	// 判断改cardId是否有过欠费
	redisResult, err = g.Redis().Get(ctx, cardId+"-arrearsBalance")
	if err != nil {
		logger.SugarLogger.Error(err.Error())
		return nil, internalerrors.New(code.ErrUnknown, err.Error())
	}
	if redisResult.Val() != nil {
		finalBalance = cast.ToFloat64(dbVo.BalanceAmt) - redisResult.Float64()
	} else {
		finalBalance = cast.ToFloat64(dbVo.BalanceAmt)
	}

	result.CardId = dbVo.CardId
	result.State = dbVo.CardStatus
	result.CardNo = dbVo.CardNo
	result.LastFourNum = dbVo.CardNo[len(dbVo.CardNo)-4:]
	result.Balance = cast.ToString(finalBalance)
	result.FirstName = cardHolderObj.FirstName
	result.LastName = cardHolderObj.LastName
	result.BillAddress = cardHolderObj.BillingAddress + " " + cardHolderObj.BillingCity + " " + cardHolderObj.BillingState + " " + cardHolderObj.BillingZipCode
	result.Email = dbVo.Email
	result.CardAlias = dbVo.CardAlias
	result.CardVerifyNo = dbVo.CardVerifyNo
	result.Expiration = dbVo.Expiration
	return result, nil
}

// 卡交易列表
func (c *cardSrv) CardTradeList(ctx context.Context, req *api.CardTradeListReq) (*page.Collection[*api.CardTradeListRes], error) {
	var (
		err        error
		resultList []*api.CardTradeListRes
		total      int
		account    string
	)
	account = ctx.Value("Account").(string)
	if len(account) == 0 {
		panic(internalerrors.New(code.ErrBind, "该帐号存在异常"))
	}
	collectionDto := &page.Collection[*api.CardTradeListRes]{}
	collectionDto.Page = req.Page
	collectionDto.PageSize = req.PageSize

	mod := global.GFDB.Ctx(ctx).Model("fx_card_trade_record fa").
		LeftJoin("SELECT card_id,card_no,deleted_at,card_alias,account,card_user_id FROM `fx_card_info`", "fa.card_id=fc.card_id").As("fc").
		LeftJoin("SELECT card_user_id,first_name,last_name,deleted_at FROM `fx_cardholder`", "fc.card_user_id=fch.card_user_id").As("fch")
	mod.Fields("fa.card_id,fa.record_no as trade_no,fc.card_no,fch.first_name,fch.last_name,fa.trans_currency_amt as amount,fa.local_currency_amt as local_amount," +
		"if(fa.trans_type='','REFUND',fa.trans_type) as trade_type,fa.created_at as trade_time,fa.trans_status as state,fa.trans_currency as currency,fa.local_currency as local_currency,fc.card_alias")
	if len(req.CardNo) > 0 {
		mod.WhereLike("fc.card_no", "%"+req.CardNo+"%")
	}
	if len(req.TradeType) > 0 {
		mod.Where("fa.trans_type=?", req.TradeType)
	}
	if len(req.StartTime) > 0 && len(req.EndTime) > 0 {
		mod.Where("fa.created_at >=? and fa.created_at <=?", req.StartTime+" 00:00:00", req.EndTime+" 23:59:59")
	}
	if len(req.TradeNo) > 0 {
		mod.WhereLike("fa.record_no", "%"+req.TradeNo+"%")
	}
	if len(req.State) > 0 {
		mod.Where("fa.trans_status=?", req.State)
	}
	mod.Where("fc.account=?", account)
	mod.Order("fa.created_at desc")
	mod.Limit(int(page.PageToOffset(req.Page, req.PageSize)), cast.ToInt(req.PageSize))
	err = mod.ScanAndCount(&resultList, &total, false)
	collectionDto.TotalPage = page.GetTotalPage(req.Page, req.PageSize, cast.ToInt64(total))

	if err != nil {
		return nil, internalerrors.New(code.ErrUnknown, "数据查询异常")
	}
	collectionDto.Total = cast.ToInt64(total)
	collectionDto.List = resultList

	return collectionDto, err
}

// 操作卡状态
func (c *cardSrv) OperatorCardState(ctx context.Context, state, cardId string) error {
	var (
		err          error
		cardInfoObj  *model.FxCardInfo
		freezeRecord *model.FxFreezeRecord
		account      string
	)
	account = ctx.Value("Account").(string)

	if err = global.GFDB.Ctx(ctx).Model("fx_card_info").Where("card_id=?", cardId).
		Scan(&cardInfoObj); err != nil {
		return internalerrors.New(code.ErrUnknown, "数据查询异常")
	}
	if state == "0" { // 需要冻结
		err = editCardStatus(ctx, &api.EditCardStatusReq{
			CardId:    cardId,
			Status:    state,
			UserReqNo: utils.GetHashCode(utils.GenerateCode32()),
		})
		if err != nil {
			return internalerrors.New(code.ErrUnknown, err.Error())
		}
		err = global.GFDB.Transaction(ctx, func(ctx context.Context, tx gdb.TX) error {
			_, err = tx.Model("fx_freeze_record").Insert(&model.FxFreezeRecord{
				CardId:       cardId,
				Account:      account,
				OperatorType: "agent",
				Operator:     state,
			})
			if err != nil {
				logger.SugarLogger.Error(err)
				return internalerrors.New(code.ErrUnknown, "冻结操作记录异常")
			}
			return nil
		})
	} else if state == "1" { // 需要解冻
		if err = global.GFDB.Ctx(ctx).Model("fx_freeze_record").
			Where("card_id=? and  operator='0'", cardId).
			Order("created_at desc").Limit(1).
			Scan(&freezeRecord); err != nil {
			return internalerrors.New(code.ErrUnknown, "操作记录查询异常")
		}
		if freezeRecord.OperatorType == "boss" {
			return internalerrors.New(code.ErrUnknown, "无法解冻")
		}
		err = editCardStatus(ctx, &api.EditCardStatusReq{
			CardId:    cardId,
			Status:    state,
			UserReqNo: utils.GetHashCode(utils.GenerateCode32()),
		})
		if err != nil {
			return internalerrors.New(code.ErrUnknown, err.Error())
		}
		err = global.GFDB.Transaction(ctx, func(ctx context.Context, tx gdb.TX) error {
			_, err = tx.Model("fx_freeze_record").Insert(&model.FxFreezeRecord{
				CardId:       cardId,
				Account:      account,
				OperatorType: "agent",
				Operator:     state,
			})
			if err != nil {
				logger.SugarLogger.Error(err)
				return internalerrors.New(code.ErrUnknown, "解冻结操作记录异常")
			}
			return nil
		})
	}
	return nil
}

// 获取代理商余额和卡使用次数(免费的)
func (c *cardSrv) GetAgentBalanceInfo(ctx context.Context) (*api.GetAgentBalanceInfoRes, error) {
	var (
		err        error
		agentObj   *model.FxAgent
		accountObj *model.FxAccount
		account    string
	)
	account = ctx.Value("Account").(string)

	if err = global.GFDB.Ctx(ctx).Model("fx_agent").Where("account=?", account).Scan(&agentObj); err != nil {
		logger.SugarLogger.Error(err)
		return nil, internalerrors.New(code.ErrUnknown, "帐号数据查询异常")
	}
	if agentObj == nil {
		return nil, internalerrors.New(code.ErrUnknown, "帐号数据异常")
	}
	if err = global.GFDB.Ctx(ctx).Model("fx_account").Where("account=?", account).Scan(&accountObj); err != nil {
		logger.SugarLogger.Error(err)
		return nil, internalerrors.New(code.ErrUnknown, "帐号数据查询异常")
	}
	if accountObj == nil {
		return nil, internalerrors.New(code.ErrUnknown, "帐号数据异常")
	}

	return &api.GetAgentBalanceInfoRes{
		Balance:        cast.ToString(accountObj.Balance),
		CardOpeningFee: cast.ToString(agentObj.CardOpeningFee),
	}, err
}

// 获取卡头信息
func (c *cardSrv) GetCardHead(ctx context.Context) (string, error) {
	var (
		err     error
		headObj *model.FxCardHead
	)
	if err = global.GFDB.Ctx(ctx).Model("fx_card_head").Fields("json").Scan(&headObj); err != nil {
		return "", internalerrors.New(code.ErrUnknown, err.Error())
	}
	return headObj.Json, err
}

// 持卡人申请
func (c *cardSrv) CardHolder(ctx context.Context, req *api.CardHolderReq) (string, error) {
	var (
		err            error
		url            = "/api/vas/cardhodler/apply"
		dataContent    string
		pubdecrypt_str string
		repObj         = &api.CardHolderVo{}
		resp           *api.CardHolderRes
	)
	repObj.FirstName = req.FirstName
	repObj.MiddleName = req.MiddleName
	repObj.LastName = req.LastName
	repObj.MobilePrefix = req.MobilePrefix
	repObj.Mobile = req.Mobile
	repObj.Email = req.Email
	repObj.CountryCode = req.CountryCode
	repObj.Remark = req.Remark
	repObj.BirthDate = req.BirthDate
	repObj.BillingAddress = req.BillingAddress
	repObj.BillingCity = req.BillingCity
	repObj.BillingState = req.BillingState
	repObj.BillingZipCode = req.BillingZipCode

	dataContent, err = OperatorParams(global.ViperObj.GetString("gep.url")+url, repObj)
	if err != nil {
		return "", internalerrors.New(code.ErrUnknown, err.Error())
	}
	// 公钥解密
	pubdecrypt_str, err = gorsa.PublicDecrypt(dataContent, gorsa.GetPublicKeyStr())
	if err != nil {
		return "", internalerrors.New(code.ErrUnknown, err.Error())
	}
	fmt.Println(dataContent)
	err = json.Unmarshal([]byte(pubdecrypt_str), &resp)
	if err != nil {
		return "", internalerrors.New(code.ErrUnknown, "申请异常")
	}
	if len(pubdecrypt_str) != 0 {
		if _, err = global.GFDB.Ctx(ctx).Model("fx_cardholder").Insert(model.FxCardholder{
			Account:        ctx.Value("Account").(string),
			CardUserId:     resp.CardUserId,
			FirstName:      req.FirstName,
			LastName:       req.LastName,
			MiddleName:     req.MiddleName,
			Email:          req.Email,
			MobilePreFix:   req.MobilePrefix,
			Mobile:         req.Mobile,
			BirthDate:      req.BirthDate,
			CountryCode:    req.CountryCode,
			BillingState:   req.BillingState,
			BillingCity:    req.BillingCity,
			BillingAddress: req.BillingAddress,
			BillingZipCode: req.BillingZipCode,
			Remark:         req.Remark,
			HolderStatus:   "3",
		}); err != nil {
			return "", internalerrors.New(code.ErrUnknown, err.Error())
		}
	}
	return resp.CardUserId, err
}

// 删除持卡人
func (c *cardSrv) DeleteCardHolder(ctx context.Context, cardUserId string) error {
	var (
		err            error
		url            = "/api/vas/cardhodler/drop"
		dataContent    string
		pubdecrypt_str string
		cardNum        int
		resp           *api.DeleteCardHolderRes
	)
	cardNum, err = global.GFDB.Ctx(ctx).Model("fx_card_info").
		Where("card_user_id=?", cardUserId).Count()
	if cardNum > 0 {
		return internalerrors.New(code.ErrUnknown, "改持卡人下已经有卡存在，不能直接删除持卡人")
	}
	dataContent, err = OperatorParams(global.ViperObj.GetString("gep.url")+url, &api.DeleteCardHolderReq{
		CardUserId: cardUserId,
	})
	if err != nil {
		return internalerrors.New(code.ErrUnknown, err.Error())
	}
	// 公钥解密
	pubdecrypt_str, err = gorsa.PublicDecrypt(dataContent, gorsa.GetPublicKeyStr())
	if err != nil {
		return internalerrors.New(code.ErrUnknown, err.Error())
	}
	err = json.Unmarshal([]byte(pubdecrypt_str), &resp)
	if err != nil {
		return internalerrors.New(code.ErrUnknown, "json转化异常")
	}
	if len(resp.CardUserId) > 0 {
		if _, err = global.GFDB.Ctx(ctx).Model("fx_cardholder").Data(g.Map{"holder_status": "2"}).
			Where("card_user_id=?", cardUserId).Update(); err != nil {
			return internalerrors.New(code.ErrUnknown, err.Error())
		}
		return nil
	}
	return internalerrors.New(code.ErrUnknown, "删除持卡人失败")
}

// 获取持卡人列表
func (c *cardSrv) GetCardHolderList(ctx context.Context, req *api.GetCardHolderListReq) (*page.Collection[*api.GetCardHolderListRes], error) {
	var (
		err        error
		resultList []*api.GetCardHolderListRes
		total      int
		account    string
	)
	account = ctx.Value("Account").(string)

	collectionDto := &page.Collection[*api.GetCardHolderListRes]{}
	collectionDto.Page = req.Page
	collectionDto.PageSize = req.PageSize

	mod := global.GFDB.Ctx(ctx).Model("fx_cardholder")
	if len(req.Name) > 0 {
		mod.WhereLike("concat(first_name,last_name)", "%"+req.Name+"%")
	}
	if len(req.Mobile) > 0 {
		mod.Where("mobile=?", req.Mobile)
	}
	if len(req.Email) > 0 {
		mod.Where("email=?", req.Email)
	}
	if len(req.HolderStatus) > 0 {
		mod.Where("holder_status=?", req.HolderStatus)
	}
	mod.Where("account=?", account)
	mod.Where("holder_status !='2'")
	mod.Order("created_at desc")
	mod.Limit(int(page.PageToOffset(req.Page, req.PageSize)), cast.ToInt(req.PageSize))
	err = mod.ScanAndCount(&resultList, &total, false)
	collectionDto.TotalPage = page.GetTotalPage(req.Page, req.PageSize, cast.ToInt64(total))

	if err != nil {
		return nil, internalerrors.New(code.ErrUnknown, "数据查询异常")
	}

	collectionDto.Total = cast.ToInt64(total)
	collectionDto.List = resultList

	return collectionDto, err
}

// 持卡人详情
func (c *cardSrv) CardHolderDetails(ctx context.Context, cardUserId string) (*api.CardHolderDetailsRes, error) {
	var (
		err       error
		resultObj *api.CardHolderDetailsRes
	)
	if err = global.GFDB.Ctx(ctx).Model("fx_cardholder").
		Where("card_user_id=?", cardUserId).Scan(&resultObj); err != nil {
		return nil, internalerrors.New(code.ErrUnknown, err.Error())
	}
	return resultObj, err
}

// 充值
func (c *cardSrv) CardRecharge(ctx context.Context, req *api.CardRechargeReq) error {
	var (
		err            error
		url            = "/api/vas/card/recharge"
		dataContent    string
		pubdecrypt_str string
		resp           *api.CardRechargeRes
		agentObj       *model.FxAgent
		userReqNo      string
		accountStr     string
		accountObj     *model.FxAccount
		finalBalance   float64
		arrearsBalance float64
		reqObj         = &api.CardRechargeVo{}
		redisResult    *gvar.Var
	)
	g.Dump(req)
	accountStr = ctx.Value("Account").(string)
	if err = global.GFDB.Model("fx_agent").Where("account", accountStr).Scan(&agentObj); err != nil {
		return internalerrors.New(code.ErrUnknown, err.Error())
	}

	if err = global.GFDB.Ctx(ctx).Model("fx_account").
		Where("account=?", accountStr).Scan(&accountObj); err != nil {
		return internalerrors.New(code.ErrUnknown, err.Error())
	}

	logger.SugarLogger.Infof("代理商账户余额：%s", accountObj.Balance.String())

	reqAmount, _ := decimal.NewFromString(req.AuthLimitAmount)
	if accountObj.Balance.LessThanOrEqual(decimal.NewFromFloat(0)) ||
		reqAmount.GreaterThan(accountObj.Balance) {
		return internalerrors.New(code.ErrUnknown, "帐号余额不足，请先充值")
	}

	finalBalance = agentObj.Fee * cast.ToFloat64(req.AuthLimitAmount)

	userReqNo = utils.GetHashCode(utils.GenerateCode32())
	reqObj.UserReqNo = userReqNo
	reqObj.ChannelType = "1"
	reqObj.CardId = req.CardId
	reqObj.AuthLimitAmount = req.AuthLimitAmount
	dataContent, err = OperatorParams(global.ViperObj.GetString("gep.url")+url, reqObj)
	if err != nil {
		return internalerrors.New(code.ErrUnknown, err.Error())
	}
	// 公钥解密
	pubdecrypt_str, err = gorsa.PublicDecrypt(dataContent, gorsa.GetPublicKeyStr())
	if err != nil {
		return internalerrors.New(code.ErrUnknown, err.Error())
	}
	err = json.Unmarshal([]byte(pubdecrypt_str), &resp)
	if err != nil {
		return internalerrors.New(code.ErrUnknown, err.Error())
	}
	if len(pubdecrypt_str) != 0 {
		// 判断改cardId是否有过欠费
		redisResult, err = g.Redis().Get(ctx, req.CardId+"-arrearsBalance")
		if err != nil {
			logger.SugarLogger.Error(err.Error())
			return internalerrors.New(code.ErrUnknown, "帐号余额不足，请先充值")
		}
		if redisResult.Val() != nil {
			arrearsBalance = redisResult.Float64()
			logger.SugarLogger.Errorf("卡所欠金额：%f", arrearsBalance)
			err = NewCardSrv().CardRefund(ctx, &api.CardRefundReq{
				CardId:       req.CardId,
				RefundAmount: cast.ToString(arrearsBalance),
				FlagBool:     true,
			})
			if err != nil {
				logger.SugarLogger.Error(err.Error())
				return internalerrors.New(code.ErrUnknown, "帐号余额不足，请先充值")
			}
			// 清除Redis中的key
			_, err = g.Redis().Del(ctx, req.CardId+"-arrearsBalance")
			if err != nil {
				logger.SugarLogger.Error(err.Error())
				return internalerrors.New(code.ErrUnknown, "帐号余额不足，请先充值")
			}
		}
		if err = DeductionBalance(finalBalance, accountStr, "admin", model.Fee, "充值手续费"); err != nil {
			return internalerrors.New(code.ErrUnknown, err.Error())
		}
		if err = DeductionAgentBalance(cast.ToFloat64(req.AuthLimitAmount), accountStr, model.Transfer, "转账费"); err != nil {
			return internalerrors.New(code.ErrUnknown, err.Error())
		}
	}
	return err
}

// 获取卡图
func (c *cardSrv) GetCardImage(ctx context.Context, cardId string) (*api.GetCardImageRes, error) {
	var (
		err    error
		url    = "/api/vas/card/v2/img"
		resp   = &api.GetCardImageRes{}
		respVo *api.GetCardImageVo
		body   []byte
	)
	body, err = json.Marshal(&api.GetCardImageReq{
		CardId: cardId,
	})
	respVo, err = SendRequestToGepToJson(global.ViperObj.GetString("gep.url")+url, string(body))
	if err != nil {
		return nil, internalerrors.New(code.ErrUnknown, err.Error())
	}
	resp.CardImgBack = respVo.CardImgBack
	resp.CardImgFront = respVo.CardImgFront
	return resp, err
}

// 获取代理商卡余额
func (c *cardSrv) GetAgentCardBalance(ctx context.Context) (string, error) {
	var (
		err     error
		account string
	)
	type DbVo struct {
		Balance string `json:"balance_amt"`
	}
	dbObj := &DbVo{}
	account = ctx.Value("Account").(string)
	if err = global.GFDB.Ctx(ctx).Model("fx_card_info").Fields("sum(balance_amt) as balance_amt").
		Where("account=?", account).Scan(dbObj); err != nil {
		return "", internalerrors.New(code.ErrUnknown, err.Error())
	}
	if len(dbObj.Balance) == 0 {
		return "0", err
	}
	return dbObj.Balance, err
}

// 获取美国各州信息
func (c *cardSrv) GetUSAStatInfo(ctx context.Context) ([]*api.GetUSAStatInfoRes, error) {
	var (
		err    error
		result = make([]*api.GetUSAStatInfoRes, 0)
	)
	if err = global.GFDB.Ctx(ctx).Model("fx_us_state").Scan(&result); err != nil {
		return nil, internalerrors.New(code.ErrUnknown, err.Error())
	}
	return result, err
}

// 卡交易退款
func (c *cardSrv) CardTradeRefundList(ctx context.Context, req *api.CardTradeRefundListReq) (*page.Collection[*api.CardTradeRefundListRes], error) {
	var (
		err        error
		resultList []*api.CardTradeRefundListRes
		total      int
		account    string
	)
	account = ctx.Value("Account").(string)

	collectionDto := &page.Collection[*api.CardTradeRefundListRes]{}
	collectionDto.Page = req.Page
	collectionDto.PageSize = req.PageSize

	mod := global.GFDB.Ctx(ctx).Model("fx_card_settlement fcs").
		Fields("fcs.origin_record_no,fcs.record_no,fci.card_no,"+
			"fc.first_name,fc.last_name,fci.card_alias,fcs.trans_currency,"+
			"fcs.trans_currency_amt,fcs.bill_currency,fcs.bill_currency_amt,fcs.settle_date,fcs.merchant_name").
		LeftJoin("fx_card_info fci", "fcs.card_id = fci.card_id").
		LeftJoin("fx_cardholder fc", "fci.card_user_id = fc.card_user_id")
	if len(req.RecordNo) > 0 {
		mod.WhereLike("fcs.origin_record_no", "%"+req.RecordNo+"%")
	}
	if len(req.CardNo) > 0 {
		mod.WhereLike("fci.card_no", "%"+req.CardNo+"%")
	}
	if len(req.StartTime) > 0 && len(req.EndTime) > 0 {
		mod.Where("fcs.settle_date >= ? and fcs.settle_date <= ?", req.StartTime, req.EndTime)
	}
	mod.Where("fci.account=?", account)
	mod.Order("fcs.settle_date desc")
	mod.Limit(int(page.PageToOffset(req.Page, req.PageSize)), cast.ToInt(req.PageSize))
	err = mod.ScanAndCount(&resultList, &total, false)
	collectionDto.TotalPage = page.GetTotalPage(req.Page, req.PageSize, cast.ToInt64(total))

	if err != nil {
		return nil, internalerrors.New(code.ErrUnknown, "数据查询异常")
	}

	collectionDto.Total = cast.ToInt64(total)
	collectionDto.List = resultList

	return collectionDto, err
}

// 退款
func (c *cardSrv) CardRefund(ctx context.Context, req *api.CardRefundReq) error {
	var (
		err            error
		url            = "/api/vas/card/refund"
		dataContent    string
		pubdecrypt_str string
		resp           *api.CardRefundRes
		userReqNo      string
		account        string
	)
	account = ctx.Value("Account").(string)
	userReqNo = utils.GetHashCode(utils.GenerateCode32())
	dataContent, err = OperatorParams(global.ViperObj.GetString("gep.url")+url, api.CardRefundVo{
		CardId:       req.CardId,
		UserReqNo:    userReqNo,
		ChannelType:  "1",
		RefundAmount: req.RefundAmount,
	})
	if err != nil {
		return internalerrors.New(code.ErrUnknown, err.Error())
	}
	// 公钥解密
	pubdecrypt_str, err = gorsa.PublicDecrypt(dataContent, gorsa.GetPublicKeyStr())
	if err != nil {
		return internalerrors.New(code.ErrUnknown, err.Error())
	}
	err = json.Unmarshal([]byte(pubdecrypt_str), &resp)
	if err != nil {
		return internalerrors.New(code.ErrUnknown, err.Error())
	}
	if len(pubdecrypt_str) != 0 {
		if !req.FlagBool {
			if err = RefundBalance(cast.ToFloat64(req.RefundAmount), account, "admin", model.Refund, "退款"); err != nil {
				return internalerrors.New(code.ErrUnknown, err.Error())
			}
		}
	}
	return err
}

// 销卡申请
func (c *cardSrv) CloseCard(ctx context.Context, req *api.CloseCardReq) error {
	var (
		err            error
		url            = "/api/vas/card/close"
		dataContent    string
		pubdecrypt_str string
		resp           *api.CloseCardRes
	)
	dataContent, err = OperatorParams(global.ViperObj.GetString("gep.url")+url, &api.CloseCardVo{
		CardId:    req.CardId,
		UserReqNo: utils.GetHashCode(utils.GenerateCode32()),
	})
	if err != nil {
		logger.SugarLogger.Error(err.Error())
		return internalerrors.New(code.ErrUnknown, err.Error())
	}
	// 公钥解密
	pubdecrypt_str, err = gorsa.PublicDecrypt(dataContent, gorsa.GetPublicKeyStr())
	if err != nil {
		logger.SugarLogger.Error(err.Error())
		return internalerrors.New(code.ErrUnknown, err.Error())
	}
	err = json.Unmarshal([]byte(pubdecrypt_str), &resp)
	if err != nil {
		logger.SugarLogger.Error(err.Error())
		return internalerrors.New(code.ErrUnknown, err.Error())
	}
	if len(pubdecrypt_str) != 0 {
		if _, err = global.GFDB.Ctx(ctx).Schema("card").
			Model("fx_card_info").Data(g.Map{"card_status": "3"}).
			Where("card_id=?", req.CardId).Update(); err != nil {
			logger.SugarLogger.Error(err.Error())
			return internalerrors.New(code.ErrUnknown, err.Error())
		}
	}
	return err
}

// 通过卡头获取对应的持卡人信息集合
func (c *cardSrv) GetCardHeadToInfo(ctx context.Context, headStr string) ([]*api.GetCardHeadToInfoRes, error) {
	var (
		err     error
		dbList  []*model.FxHolderHead
		result  = make([]*api.GetCardHeadToInfoRes, 0)
		account string
	)
	account = ctx.Value("Account").(string)
	if err = global.GFDB.Ctx(ctx).Model("fx_cardholder fc").
		Fields("fh.card_user_id,fh.first_name,fh.last_name,fh.country_code").
		LeftJoin("fx_holder_head fh", "fc.card_user_id=fh.card_user_id").
		Where("account=? and find_in_set(?, fh.card_head)", account, headStr).Scan(&dbList); err != nil {
		return nil, internalerrors.New(code.ErrUnknown, err.Error())
	}
	for _, value := range dbList {
		result = append(result, &api.GetCardHeadToInfoRes{
			CardUserId:  value.CardUserId,
			FirstName:   value.FirstName,
			LastName:    value.LastName,
			CountryCode: value.CountryCode,
		})
	}
	return result, err
}

// 手动充值记录
func (c *cardSrv) ManualCardRechargeRecord(ctx context.Context, req *api.ManualCardRechargeRecordReq) error {
	var (
		err error
	)
	// 充值手续费
	if err = DeductionBalance(req.FeeAmount, req.Account, "admin", model.Fee, req.RecordDesc); err != nil {
		logger.SugarLogger.Error(err)
		return internalerrors.New(code.ErrUnknown, err.Error())
	}
	// 转账费
	if err = DeductionAgentBalance(req.TransferAmount, req.Account, model.Transfer, req.RecordDesc); err != nil {
		logger.SugarLogger.Error(err)
		return internalerrors.New(code.ErrUnknown, err.Error())
	}
	return err
}

// 手动扣除代理商金额
func (c *cardSrv) ManualDeductionAgentBalance(ctx context.Context, req *api.ManualDeductionAgentBalanceReq) error {
	var (
		err error
	)
	if err = DeductionAgentBalance(req.Amount, req.Account, req.RecordType, req.RecordDesc); err != nil {
		logger.SugarLogger.Error(err)
		return internalerrors.New(code.ErrUnknown, err.Error())
	}
	return nil
}

// 卡片信息修改(状态)
func editCardStatus(ctx context.Context, req *api.EditCardStatusReq) error {
	var (
		err            error
		url            = "/api/vas/card/modifyCard"
		dataContent    string
		pubdecrypt_str string
		resp           *api.EditCardStatusRes
		statusDesc     string
	)
	req.UserReqNo = utils.GetHashCode(utils.GenerateCode32())
	dataContent, err = OperatorParams(global.ViperObj.GetString("gep.url")+url, req)
	if err != nil {
		return internalerrors.New(code.ErrUnknown, err.Error())
	}
	// 公钥解密
	pubdecrypt_str, err = gorsa.PublicDecrypt(dataContent, gorsa.GetPublicKeyStr())
	if err != nil {
		return internalerrors.New(code.ErrUnknown, err.Error())
	}
	err = json.Unmarshal([]byte(pubdecrypt_str), &resp)
	if err != nil {
		return internalerrors.New(code.ErrUnknown, err.Error())
	}
	if len(pubdecrypt_str) != 0 {
		if req.Status == "1" {
			statusDesc = "使用中"
		} else if req.Status == "0" {
			statusDesc = "冻结"
		}
		if _, err = global.GFDB.Ctx(ctx).Schema("card").Model("fx_card_info").Data(g.Map{
			"card_status":      req.Status,
			"card_status_desc": statusDesc,
		}).Where("card_id=?", req.CardId).Update(); err != nil {
			logger.SugarLogger.Error(err.Error())
			return internalerrors.New(code.ErrUnknown, "卡信息修改失败")
		}
	}
	return err
}

func requestCardInfo(cardId string) error {
	var (
		err            error
		url            = "/api/vas/card/info"
		dataContent    string
		pubdecrypt_str string
		resp           *api.CardInfoRes
		cardInfoObj    = &model.FxCardInfo{}
	)
	dataContent, err = OperatorParams(global.ViperObj.GetString("gep.url")+url, &api.GetCardInfoReq{
		CardId: cardId,
	})
	if err != nil {
		return internalerrors.New(code.ErrUnknown, err.Error())
	}
	// 公钥解密
	pubdecrypt_str, err = gorsa.PublicDecrypt(dataContent, gorsa.GetPublicKeyStr())
	if err != nil {
		return internalerrors.New(code.ErrUnknown, err.Error())
	}
	err = json.Unmarshal([]byte(pubdecrypt_str), &resp)
	if err != nil {
		return internalerrors.New(code.ErrUnknown, err.Error())
	}
	if err = global.GFDB.Schema("card").Model("fx_card_info").
		Where("card_id=?", cardId).
		Scan(&cardInfoObj); err != nil {
		return internalerrors.New(code.ErrUnknown, err.Error())
	}
	if len(pubdecrypt_str) > 0 {
		if _, err = global.GFDB.Schema("card").Model("fx_card_info").Data(g.Map{
			"start_active_date":     resp.StartActiveDate,
			"end_close_date":        resp.EndCloseDate,
			"credit_limit_amt":      resp.CreditLimitAmt,
			"min_auth_amt":          resp.MinAuthAmt,
			"max_auth_amt":          resp.MaxAuthAmt,
			"balance_amt":           resp.BalanceAmt,
			"used_auth_amt":         resp.UsedAuthAmt,
			"enable_multi_use":      resp.EnableMultiUse,
			"enable_currency_check": resp.EnableCurrencyCheck,
			"card_closed_amt":       resp.CardClosedAmt,
			"card_status":           resp.CardStatus,
			"card_status_desc":      resp.CardStatusDesc,
			"create_card_time":      resp.CreateTime,
			"card_alias":            resp.CardAlias,
		}).Where("card_id=?", cardId).Update(); err != nil {
			logger.SugarLogger.Error(err.Error())
			return internalerrors.New(code.ErrUnknown, err.Error())
		}
		if _, err = global.GFDB.Schema("card").Model("fx_cardholder").Data(g.Map{
			"country":          resp.BillAddressInfo.Country,
			"country_code":     resp.BillAddressInfo.CountryCode,
			"billing_state":    resp.BillAddressInfo.BillingState,
			"billing_city":     resp.BillAddressInfo.BillingCity,
			"billing_address":  resp.BillAddressInfo.BillingAddress,
			"billing_zip_code": resp.BillAddressInfo.BillingZipCode,
			"first_name":       resp.CardUserInfo.FirstName,
			"last_name":        resp.CardUserInfo.LastName,
			//"mobile":           resp.CardUserInfo.Mobile,
			"email":      resp.CardUserInfo.Email,
			"birth_date": resp.CardUserInfo.BirthDate,
		}).Where("card_user_id=?", cardInfoObj.CardUserId).Update(); err != nil {
			logger.SugarLogger.Error(err.Error())

			return internalerrors.New(code.ErrUnknown, err.Error())
		}
	}
	return err
}

func GetNumerFirst(cardHead string) string {
	firstDigitChar := cardHead[0] // 获取字符串的第一个字符
	// 如果你想得到这个字符对应的数字
	firstDigit := firstDigitChar - '0' // 将字符转换为对应的整数
	return cast.ToString(firstDigit)
}
